;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;scroll-bar dialog-items
;;
;;  copyright © 1987-89 Apple Computer
;;
;;the code in this file implements a scroll-bar class of dialog-items
;;


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; a few things that need to be around at compile time, but not run time
;;
(eval-when (eval compile)

  ;some constants for tracking the clicks in the scroll-bar
  (defconstant $InUpButton 20)
  (defconstant $InDownButton 21)
  (defconstant $InPageUp 22)
  (defconstant $InPageDown 23)
  (defconstant $InThumb 129)

  ;trap macros compiled away into in-line calls
  (require 'traps))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;*scroll-bar-dialog-item*
;;
;;this class inherits from *user-dialog-item*
;;

(defobject *scroll-bar-dialog-item* *user-dialog-item*)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;exist
;;
;;init-list keywords:
;;   scroll-bar-length
;;   direction
;;   setting
;;   min-setting
;;   max-setting
;;   page-size
;;
;;in addition, the standard dialog-item init-list keywords can be used
;;

(defobfun (exist *scroll-bar-dialog-item*) (init-list)
  (declare (object-variable min-setting max-setting direction scroll-bar-length))
  (have 'scroll-bar-length (getf init-list :scroll-bar-length 100))
  (have 'direction (getf init-list :direction :vertical))
  (have 'min-setting (getf init-list :min-setting 0))
  (have 'max-setting (getf init-list :max-setting (max min-setting 100)))
  (have 'setting (getf init-list :setting (min (max 0 min-setting)
                                               max-setting)))
  (have 'page-size (getf init-list :page-size 5))
  (usual-exist (init-list-default init-list
                                  :dialog-item-size
                                  (case direction
                                    (:vertical (make-point 16
                                                           scroll-bar-length))
                                    (:horizontal (make-point scroll-bar-length
                                                             16))
                                    (t (error "illegal :direction ~a (must be :vertical or :horizontal)."
                                              direction))))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;add-self-to-dialog
;;
;;  this is when we actually create the control (when the item
;;  is added to a window)

(defobfun (add-self-to-dialog *scroll-bar-dialog-item*) (dialog)
  (declare (object-variable wptr setting min-setting max-setting))
  (usual-add-self-to-dialog dialog)
  (let* ((my-size (dialog-item-size))
         (my-position (dialog-item-position)))
    (rlet ((scroll-rect :rect))
      (rset scroll-rect rect.topleft my-position)
      (rset scroll-rect rect.bottomright (add-points my-position my-size))
      (have 'dialog-item-handle
            (_NewControl :ptr (ask dialog wptr)         ;window
                         :ptr scroll-rect               ;item rectangle
                         :ptr 0                         ;title
                         :word -1                       ;visible
                         :word setting                  ;initial value
                         :word min-setting              ;min value
                         :word max-setting              ;max value
                         :word 16                       ;type of control
                         :long 0                        ;refcon
                         :ptr)))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;dialog-item-draw
;;
;;this function is called whenever the item needs to be drawn
;;
;;to draw the dialog-item, we just call _Draw1Control
;;

(defobfun (dialog-item-draw *scroll-bar-dialog-item*) ()
  (declare (object-variable dialog-item-handle))
  (_Draw1Control :ptr dialog-item-handle))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;dialog-item-click-event-handler
;;
;;this is the function which is called when the user clicks in the scroll-bar
;;
;;It checks the scroll-bar part, and calls _TrackControl
;;  If appropriate, it passes a hook function to _TrackControl
;;
;;During tracking, dialog-item-action is repeatedly called.
;;

(defobfun (dialog-item-click-event-handler *scroll-bar-dialog-item*) (where)
  (declare (object-variable dialog-item-handle scroll-bar-proc))
  (let* ((sb-handle dialog-item-handle)
         (part (_TestControl :ptr sb-handle :long where :word)))
    (if (eq part #.$InThumb)
        (progn
          (_TrackControl :ptr sb-handle
                         :long where
                         :ptr -1
                         :word)
          (dialog-item-action))
        (_TrackControl :ptr sb-handle
                       :long where
                       :ptr scroll-bar-proc
                       :word))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;scroll-bar-proc
;;
;;this is the hook function which is passed to _TrackControl.  The toolbox
;;  will call this function periodically as the control is clicked.
;;

(defpascal scroll-bar-proc ((sb-handle :ptr) (part :word))
  (declare (object-variable page-size))
  "This procedure adjusts the control value, and calls dialog-item-action."
  (_SetCtlValue :ptr sb-handle :word
    (+ (_GetCtlValue :ptr sb-handle :word)
       (case part
         (#.$InUpButton -1)
         (#.$InDownButton 1)
         (#.$InPageUp (- page-size))
         (#.$InPageDown page-size)
         (t 0))))
    (dialog-item-action))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;scroll-bar-value
;;
;;a nice safe Lisp-level function for getting the value of the scroll-bar
;;

(defobfun (scroll-bar-value *scroll-bar-dialog-item*) ()
  (declare (object-variable dialog-item-handle))
  (_GetCtlValue :ptr dialog-item-handle :word))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;set-scroll-bar-value
;;
;;a nice safe Lisp-level function for changing the value of the scroll-bar
;;

(defobfun (set-scroll-bar-value *scroll-bar-dialog-item*) (new-value)
  (declare (object-variable dialog-item-handle))
  (if (fixnump new-value)
      (_SetCtlValue :ptr dialog-item-handle :word new-value)
      (error "~a is not a fixnum." new-value)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;scroll-bar-length
;;
;;this is a variation of dialog-item-size
;;
;;It only used one dimension, since scroll-bars almost always have a width
;;  of 16 pixels.
;;

(defobfun (scroll-bar-length *scroll-bar-dialog-item*) ()
  (declare (object-variable direction))
  (let ((size (dialog-item-size)))
    (if (eq direction :horizontal)
        (point-h size)
        (point-v size))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;set-scroll-bar-length
;;
;;sets the length of the scroll-bar
;;

(defobfun (set-scroll-bar-length *scroll-bar-dialog-item*) (new-length)
  (declare (object-variable direction))
  (set-dialog-item-size (if (eq direction :horizontal)
                            (make-point new-length 16)
                            (make-point 16 new-length))))

(provide 'scroll-bars)

#|
;; a simple example use

(setq my-dialog (oneof *dialog*
                       :window-size #@(250 75)
                       :window-title "Scroll Bar Example"))

(ask my-dialog (add-dialog-items
                (have 'display-text
                      (oneof *static-text-dialog-item* :dialog-item-text "000"))
                (oneof *scroll-bar-dialog-item*
                       :dialog-item-position #@(25 50)
                       :direction :horizontal
                       :scroll-bar-length 200
                       :dialog-item-action
                       #'(lambda (&aux (setting (format nil "~a" (scroll-bar-value))))
                           (ask my-dialog
                             (ask display-text
                               (set-dialog-item-text setting)))))))

|#

